#ifndef UNIAST_RUNTIME_EXPRESSION_H
#define UNIAST_RUNTIME_EXPRESSION_H

#include "mlir/IR/Value.h"
#include "symbolTable/Variable.h"
#include "type/Type.h"
#include <memory>
#include <shared_mutex>
#include <vector>

namespace UniAST
{
class RightValue
{
  private:
    mlir::Value mlirValue;
    std::shared_ptr<UniAST::Type> exprtype;

  public:
    virtual ~RightValue() = default;
    RightValue(std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirValue = nullptr);
    void setmlirValue(mlir::Value value);
    mlir::Value getmlirValue();
    void setType(std::shared_ptr<UniAST::Type> exprtype);
    std::shared_ptr<UniAST::Type> getType();
};

class Expression : public RightValue
{
  public:
    enum class OPERATOR
    {
        ADD,
        SUB,
        MUL,
        DIV
    };

  private:
    std::vector<std::shared_ptr<RightValue>> exprParams;
    OPERATOR op;

  public:
    Expression(OPERATOR op,
               std::vector<std::shared_ptr<RightValue>> exprParams,
               std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirvalue = nullptr);
    static std::shared_ptr<Expression>
    get(std::vector<std::shared_ptr<RightValue>> params, OPERATOR op,
        mlir::Value mlirvalue = nullptr);
};

class PrimaryExpression : public RightValue
{
  public:
    PrimaryExpression(std::shared_ptr<UniAST::Type> exprtype,
                      mlir::Value mlirValue = nullptr);
};

class VariableAccess : public PrimaryExpression
{
  private:
    std::shared_ptr<Variable> var;

  public:
    VariableAccess(std::shared_ptr<Variable> var, std::shared_ptr<UniAST::Type> exprtype,
                   mlir::Value mlirValue = nullptr);
    static std::shared_ptr<VariableAccess>
    get(std::shared_ptr<Variable> var, mlir::Value mlirValue);
};

class Literal : public PrimaryExpression
{
  public:
    Literal(std::shared_ptr<UniAST::Type> exprtype, mlir::Value mlirValue = nullptr);
};

class IntergerLiteral : public Literal
{
  private:
    long int content;

  public:
    IntergerLiteral(long int content, mlir::Value mlirValue);
    static std::shared_ptr<IntergerLiteral> get(long int content,
                                                mlir::Value mlirValue);
};

class FloatPointLiteral : public Literal
{
  private:
    double content;

  public:
    FloatPointLiteral(double content);
};
} // namespace UniAST

#endif